package top.crossrun.webview.bridge.core.utils;

import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.os.Looper;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

import top.crossrun.webview.bridge.core.pls.WebViewActivityLife;
import top.crossrun.webview.bridge.core.pls.BridgeCallBackFunction;
import top.crossrun.webview.bridge.core.pls.WebViewBridgeHandler;
import top.crossrun.webview.bridge.core.pls.BridgeJSEval;
import top.crossrun.webview.bridge.core.pls.WebViewActivityRegister;
import top.crossrun.webview.bridge.core.pls.WebViewBridgePluginManager;
import top.crossrun.webview.bridge.core.pls.WebViewBridgePluginManagerAdapter;
import top.crossrun.webview.bridge.core.pls.WebViewBridgePlugin;

public class BridgeHelper implements WebViewActivityLife, WebViewActivityRegister {

    private String kCustomProtocolScheme = "wvbj";
    private String kCustomreturnHost = "return";
    private String kQueueHasMessage = "__QUEUE_MESSAGE__";

    private WebViewBridgePluginManager bridgePluginManager;

    private ArrayList<BridgeMessage> startupMessageQueue;
    private Map<String, BridgeCallBackFunction> responseCallbacks;
    private long uniqueId = 0;
    private WebViewBridgePlugin messageHandler;

    public BridgeHelper(final Activity activity, BridgeJSEval jsEval) {
        this(new WebViewBridgePluginManagerAdapter(jsEval) {
            @Override
            public Activity getActivityContext() {
                return activity;
            }
        });
    }

    public BridgeHelper(WebViewBridgePluginManager bridgePluginInterface) {
        this(bridgePluginInterface, null);
    }

    /**
     * @param bridgePluginManager 插件处理
     * @param messageHandler      所有没找对应名字的消息处理 可以为空
     */
    public BridgeHelper(WebViewBridgePluginManager bridgePluginManager, WebViewBridgePlugin messageHandler) {
        this.bridgePluginManager = bridgePluginManager;
        this.responseCallbacks = new HashMap<>();
        this.startupMessageQueue = new ArrayList<>();
        this.messageHandler = messageHandler;
    }

    /**
     * @param bridgePluginManager 插件处理
     * @param scheme              特殊协议头
     * @param hasMessage          分发消息的host
     */
    public BridgeHelper(WebViewBridgePluginManager bridgePluginManager, String scheme, String hasMessage) {
        this.bridgePluginManager = bridgePluginManager;
        this.responseCallbacks = new HashMap<>();
        this.startupMessageQueue = new ArrayList<>();

    }

    public boolean shouldOverrideUrlLoading(String url) {
        return shouldOverrideUrlLoading(url, false);
    }


    /**
     * 需要在WebViewClien.shouldOverrideUrlLoading里面添加
     * <p>
     * public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
     * if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
     * helper.shouldOverrideUrlLoadingl(request.getUrl().toString());
     * } else {
     * helper.shouldOverrideUrlLoading(request.toString());
     * }
     * return super.shouldOverrideUrlLoading;
     * }
     *
     * @param url  url
     * @param flag true = 处理可以跳转的url;false = 不处理
     * @return true=处理了;false=未处理
     */
    public boolean shouldOverrideUrlLoading(String url, boolean flag) {
        if (url.startsWith(kCustomProtocolScheme)) {
            if (url.indexOf("return") > 0) {
                handlerReturnData(url);
            } else if (url.indexOf(kQueueHasMessage) > 0) {
                flushMessageQueue();
            }
            return true;
        } else if (flag &&!url.startsWith("http")) {
            Intent in = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
            in.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            if (BridgeUtil.isIntentAvailable(bridgePluginManager.getActivityContext(), in)) {
                bridgePluginManager.getActivityContext().startActivity(in);
                return true;
            }
        }
        return false;
    }

    /**
     * 需要在WebViewClien.onPageFinished
     *
     * @param url url
     */
    public void onPageFinished(String url) {
        executeJavascript(bridgePluginManager.getBridgeJS());
        if (startupMessageQueue != null) {
            for (BridgeMessage var4 : startupMessageQueue) {
                dispatchMessage(var4);
            }
            startupMessageQueue = null;
        }
    }

    /**
     * 注册方法供js调用
     *
     * @param handlerName 方法名，不可为空
     * @param handler     执行逻辑，不可为空
     * @param needContext 收到命令时获取不到context，是否中断插件执行，true=中断
     */
    @Override
    public void pluginRegister(String handlerName, WebViewBridgeHandler handler, boolean needContext) {
        bridgePluginManager.pluginRegister(handlerName, handler, needContext);
    }

    /**
     * 注册方法供js调用
     *
     * @param handler 封装的
     */
    @Override
    public void pluginRegister(WebViewBridgePlugin handler) {
        bridgePluginManager.pluginRegister(handler);
    }

    @Override
    public void pluginRegister(String name, Class<? extends WebViewBridgePlugin> s) {
        bridgePluginManager.pluginRegister(name, s);
    }

    /**
     * 调用Html里面的js，
     *
     * @param handlerName      js里面注册的名字，不能为空
     * @param data             参数，可以为空
     * @param responseCallback 回调，可以为空
     */
    public void callHandler(String handlerName, String data,
                            BridgeCallBackFunction responseCallback) {
        sendData(data, responseCallback, handlerName);
    }

    private void sendData(String data, BridgeCallBackFunction responseCallback,
                          String handlerName) {
        if (data == null && (handlerName == null || handlerName.length() == 0))
            return;
        BridgeMessage message = new BridgeMessage();
        if (data != null) {
            message.data = data;
        }
        if (responseCallback != null) {
            String callbackId = "cb_" + (++uniqueId);
            responseCallbacks.put(callbackId, responseCallback);
            message.callbackId = callbackId;
        }
        if (handlerName != null) {
            message.handlerName = handlerName;
        }
        queueMessage(message);
    }

    private void queueMessage(BridgeMessage message) {
//        log("queueMessage = " + message.toJson());
        if (startupMessageQueue != null) {
            startupMessageQueue.add(message);
        } else {
            dispatchMessage(message);
        }
    }

    private void dispatchMessage(BridgeMessage message) {
//        log("dispatchMessage = " + message.toJson());
        String var2 = message.toJson().replaceAll("(\\\\)([^utrn])", "\\\\\\\\$1$2").replaceAll("(?<=[^\\\\])(\")", "\\\\\"");
        var2 = String.format("javascript:WebViewJavascriptBridge._handleMessageFromNative('%s');", var2);
        if (Thread.currentThread() == Looper.getMainLooper().getThread()) {
            bridgePluginManager.loadUrl(var2);
        }
    }

    private void executeJavascript(String script) {
        executeJavascript(script, null);
    }

    private void executeJavascript(String script,
                                   final BridgeCallBackFunction callback) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            BridgeJSEval jsEval = bridgePluginManager.getJSEval();
            jsEval.evaluateJavascript(script, callback);
        } else {
            bridgePluginManager.loadUrl("javascript:" + script);
        }
//        log("executeJavascript = " + BridgeUtil.parseFunctionName(script));
        responseCallbacks.put(BridgeUtil.parseFunctionName(script), callback);
    }

    private void flushMessageQueue() {
//        log("flushMessageQueue");
        String script = "javascript:WebViewJavascriptBridge._fetchQueue();";
        executeJavascript(script, new BridgeCallBackFunction() {
            @Override
            public void onCallBackFunction(String msg) {
                if (msg == null
                        || msg.length() == 0)
                    return;
                processQueueMessage(msg);
            }
        });
    }

    private void processQueueMessage(String messageQueueString) {
//        log("processQueueMessage " + messageQueueString);
        try {
            JSONArray messages = new JSONArray(messageQueueString);
            for (int i = 0; i < messages.length(); i++) {
                JSONObject jo = messages.getJSONObject(i);

                BridgeMessage message = JSONObject2WVJBMessage(jo);
                if (message.responseId != null) {
                    BridgeCallBackFunction responseCallback = responseCallbacks
                            .remove(message.responseId);
                    if (responseCallback != null) {
                        responseCallback.onCallBackFunction(message.responseData == null ? "" : message.responseData.toString());
                    }
                } else {
                    BridgeCallBackFunction responseCallback = null;
                    if (message.callbackId != null) {
                        final String callbackId = message.callbackId;
                        responseCallback = new BridgeCallBackFunction() {
                            @Override
                            public void onCallBackFunction(String data) {
                                BridgeMessage msg = new BridgeMessage();
                                msg.responseId = callbackId;
                                msg.responseData = data;
                                queueMessage(msg);
                            }
                        };
                    }

                    WebViewBridgePlugin handler;
                    if (message.handlerName != null) {
                        handler = bridgePluginManager.getBridgePlugin(message.handlerName);
                    } else {
                        handler = messageHandler;
                    }
                    if (handler != null) {
                        handler._handlerBridgeMsg(message.data == null ? "" : message.data, responseCallback);
                    }
                }
            }
        } catch (JSONException e) {
//            e.printStackTrace();
        }
    }

    public void handlerReturnData(String var1) {
        String var2 = BridgeUtil.getFunctionFromReturnUrl(kCustomProtocolScheme, kCustomreturnHost, var1);
        BridgeCallBackFunction var3 = this.responseCallbacks.get(var2);
        var1 = BridgeUtil.getDataFromReturnUrl(kCustomProtocolScheme, kCustomreturnHost, var1);
        if (var3 != null) {
            var3.onCallBackFunction(var1);
            this.responseCallbacks.remove(var2);
        }
    }

    private BridgeMessage JSONObject2WVJBMessage(JSONObject jo) {
        BridgeMessage message = new BridgeMessage();
        try {
            if (jo.has("callbackId")) {
                message.callbackId = jo.getString("callbackId");
            }
            if (jo.has("data")) {
                message.data = jo.getString("data");
            }
            if (jo.has("handlerName")) {
                message.handlerName = jo.getString("handlerName");
            }
            if (jo.has("responseId")) {
                message.responseId = jo.getString("responseId");
            }
            if (jo.has("responseData")) {
                message.responseData = jo.get("responseData");
            }
        } catch (JSONException e) {
            e.printStackTrace();
        }
        return message;
    }

    /**
     * 自定义协议头
     *
     * @param kCustomProtocolScheme wvbj
     * @return
     */
    public BridgeHelper setkCustomProtocolScheme(String kCustomProtocolScheme) {
        this.kCustomProtocolScheme = kCustomProtocolScheme;
        return this;
    }

    /**
     * 自定义返回数据的host
     *
     * @param kCustomreturnHost 默认=return
     * @return
     */
    public BridgeHelper setkCustomreturnHost(String kCustomreturnHost) {
        this.kCustomreturnHost = kCustomreturnHost;
        return this;
    }

    /**
     * 自定义消息连接的host
     *
     * @param kQueueHasMessage 默认__QUEUE_MESSAGE__
     * @return
     */
    public BridgeHelper setkQueueHasMessage(String kQueueHasMessage) {
        this.kQueueHasMessage = kQueueHasMessage;
        return this;
    }

    @Override
    public void onResume() {
        bridgePluginManager.onResume();
    }

    @Override
    public void onPause() {
        bridgePluginManager.onPause();
    }

    @Override
    public void onStart() {
        bridgePluginManager.onStart();
    }

    @Override
    public void onStop() {
        bridgePluginManager.onStop();
    }

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        bridgePluginManager.onActivityResult(requestCode, resultCode, data);
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
        bridgePluginManager.onRequestPermissionsResult(requestCode, permissions, grantResults);
    }

    @Override
    public void onDestroy() {
        if (startupMessageQueue != null) {
            startupMessageQueue.clear();
        }
        if (responseCallbacks != null) {
            responseCallbacks.clear();
        }
        if (bridgePluginManager != null) {
            bridgePluginManager.onDestroy();
        }
        bridgePluginManager = null;
        if (messageHandler != null) {
            messageHandler.onDestroy();
        }
        messageHandler = null;
    }

    @Override
    public WebViewBridgePlugin getBridgePlugin(String name) {
        return bridgePluginManager.getBridgePlugin(name);
    }

    public static class BridgeMessage {
        String data = null;
        String callbackId = null;
        String handlerName = null;
        String responseId = null;
        Object responseData = null;

        public String toJson() {
            JSONObject var1 = new JSONObject();

            try {
                var1.put("callbackId", callbackId);
                var1.put("data", data);
                var1.put("handlerName", handlerName);
                var1.put("responseData", responseData);
                var1.put("responseId", responseId);
                return var1.toString();
            } catch (JSONException var2) {
                var2.printStackTrace();
                return null;
            }
        }
    }

//    private void log(String msg) {
//        Log.e("console", "Android | " + msg);
//    }

}
